#include "fxcc/core/graph/opengl3/impl.h"
#include "fxcc/core/graph/common/Geometry.h"

using namespace fxcc::platform;
using namespace fxcc::graph;
using namespace fxcc::graph::opengl3;

#undef main

const int numObjs = 20;

struct Object
{
	fxcc::graph::common::Transform transform;
	std::shared_ptr<fxcc::graph::common::Mesh> mesh;
};
struct SimpleApp :public opengl3::GlfwApp
{
	std::vector<fxcc::graph::common::VertexFixed> m_Vertices;
	std::shared_ptr<fxcc::graph::opengl3::RenderTarget> m_RenderTarget;
	std::shared_ptr<fxcc::graph::opengl3::Texture2D> m_Texture;

	glm::vec4 color;
	std::shared_ptr<fxcc::graph::opengl3::Effect3d> m_Effect;
	std::shared_ptr<fxcc::graph::opengl3::Effect2d> m_ImageEffect;

	std::vector<Object> m_objects;
	fxcc::graph::common::Camera camera;

	SimpleApp(const fxcc::platform::common::App::Desc& desc) :opengl3::GlfwApp(desc), color(1.0)
	{

	}
	void printOpenGLESVersion()
	{
		const char *version = (const char *)glGetString(GL_VERSION);
		std::cout << "OpenGL ES Version: " << version << std::endl;
	}
	bool InitResources() override
	{

		camera.SetPosition(glm::vec3(5.0f));
		camera.LookAt(glm::vec3(0.0f));
		const std::string fragCode = R"(

out vec4 FragColor;

uniform sampler2D diffuse;

void main()
{
	FragColor=texture(diffuse,TexCoord);
}
)";
		m_Effect = std::make_shared<fxcc::graph::opengl3::Effect3d>(fragCode);
		
		const std::string imageFragCode = R"(

out vec4 FragColor;

uniform sampler2D diffuse;

void main()
{
	FragColor=texture(diffuse,TexCoord);
}
)";
		m_ImageEffect = std::make_shared<fxcc::graph::opengl3::Effect2d>(imageFragCode);

		auto &am = fxcc::AssertManager::Inst();
		std::string imagePath = am.GetFile("textures/container.jpg");
		std::cout << imagePath << std::endl;
		m_Texture = std::make_shared<fxcc::graph::opengl3::Texture2D>(imagePath);

		auto geoData = fxcc::graph::common::Geometry::CreateBox();
		fxcc::graph::common::MeshDesc meshDesc(geoData);
		auto cubeMesh = std::make_shared<fxcc::graph::opengl3::Mesh>(meshDesc);
		
		m_objects.resize(numObjs);
		fxcc::graph::common::Random random;
		std::vector<fxcc::graph::common::Transform> transforms = random.GenerateTransforms(numObjs);

		for (int i = 0; i < numObjs; i++)
		{
			m_objects[i].transform = transforms[i];
			m_objects[i].mesh = cubeMesh;
		}
		return true;
	};

	void OnFrameRender() override
	{
		glViewport(0, 0, m_Desc.m_Size.x, m_Desc.m_Size.y);

		glClearColor(color.x, color.y, color.z, color.w);
		glClear(GL_COLOR_BUFFER_BIT);

		//m_RenderTarget->Begin();
		
		m_Effect->Begin();
		m_Effect->SetCamera(camera);
		m_Effect->m_Shader->Use();
		m_Effect->m_Shader->setInt("diffuse", 1);
		m_Texture->Active(1);

		for (const auto& obj : m_objects)
		{
			m_Effect->InstMesh(obj.mesh.get(), obj.transform);

		}
		m_Effect->End();

		//m_ImageEffect->Begin();
		//m_ImageEffect->End();

		//m_RenderTarget->End();
	};

	void OnFramebuffersize(int w, int h) override
	{
		opengl3::GlfwApp::OnFramebuffersize(w, h);
		camera.SetAspect(m_Desc.Aspect());
		
		//{
		//	fxcc::graph::common::RenderTargetDesc desc;
		//	desc.InitDesc2(1, w, h);
		//	m_RenderTarget = std::make_shared<fxcc::graph::opengl3::RenderTarget>(desc);
		//}
	}
	void OnUpdate() override
	{
		opengl3::GlfwApp::OnUpdate();

		float ctTime = m_GlfwlTimer.m_CurrentTime;
		camera.FreeMove(m_Input ,m_GlfwlTimer.m_DeltaTime);

	}
};

int main()
{
	ztclog::pushFunction([](const ztclog::Line& line) {
		if (line.m_Type != ztclog::Line::Type::_line_debug_)
		{
			std::cout << line.m_Text << std::endl;
		}
		});

	using _App = SimpleApp;
	using _Desc = fxcc::platform::common::App::Desc;

	_Desc desc;
	desc.m_Pos = glm::ivec2(100, 100);
	desc.m_Size = glm::ivec2(1200, 900);
	desc.m_ScaleFactor = 1.0f;

	desc.m_Title = "test graph";
	std::shared_ptr<_App> _app = std::make_shared<_App>(desc);
	return _app->Run();

}